#include "head.h"

int socket_des, local = 1;
pthread_t thread;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void * request(void * args) {
	task_type task;
	socklen_t addr_length;
	struct sockaddr * sr_address;
	struct sockaddr_un unix_sr_address;
	struct sockaddr_in inet_sr_address;
	FILE * fp;
	char * buffer = (char *)malloc(sizeof(char)*2000);
	if (local == 1) {
		sr_address = (struct sockaddr *)&unix_sr_address;
		addr_length = SUN_LEN(&unix_sr_address);
	} else {
		sr_address = (struct sockaddr *)&inet_sr_address;
		addr_length = sizeof(inet_sr_address);
	}
	while (1) {
		sleep(1);
		pthread_mutex_lock(&mutex);
		int tmp;
		if ((tmp = recvfrom(socket_des, (void *)&task, sizeof(task), MSG_DONTWAIT, sr_address, &addr_length)) == -1) {
			if (errno != EAGAIN && errno != EWOULDBLOCK) {
				perror("recvfrom");
				exit(1);
			}
		} else if (task.action == 2) {
			printf("Dostałem żądanie wykonania polecenia\n");
			printf("Polecenie: %s: %s\n", task.name, task.command);
			printf("%d\n",tmp);
			if ((fp = popen(task.command, "r")) == NULL) {
				perror("popen");
				exit(2);
			}
			fscanf(fp, "%s", buffer);
			printf("%s\n", buffer);
			if(sendto(socket_des, (void *)&buffer, sizeof(char)*2000, 0, sr_address, addr_length) == -1) {
				perror("sendto");
				exit(3);
			}
		}
		pthread_mutex_unlock(&mutex);
	}
}

int main(int argc, char ** argv) {
	int server_port;
	char server_path[128], *ip;
	char client_name[32], client_path[128];
	if (argc < 2) {
		printf("Niepoprawne wywołanie. Poprawne wywołanie: ./klient.o <unix|inet> <<path>|<ip> <port>>\n");
		return -1;
	}
	if (strcmp(argv[1], "unix") == 0) {
		if (argc != 3) {
			printf("Niepoprawne wywołanie. Poprawne wywołanie: ./klient.o <unix|inet> <<path>|<ip> <port>>\n");			
			return -2;
		}
		local = 1;
		strcpy(server_path, argv[2]);
	} else if (strcmp(argv[1], "inet") == 0) {
		if (argc != 4) {
			printf("Niepoprawne wywołanie. Poprawne wywołanie: ./klient.o <unix|inet> <<path>|<ip> <port>>\n");
			return -3;
		}
		local = 0;
		ip = argv[2];
		server_port = atoi(argv[3]);
		if (server_port <= 0) {
			printf("Port musi być liczbą dodatnią całkowitą\n");
			return -4;
		}
	} else {
		printf("Niepoprawne wywołanie. Poprawne wywołanie: ./klient.o <unix|inet> <<path>|<ip> <port>>\n");		
		return -5;
	}
	printf("Generuję hosta i domenę\n");
	//char host[32], * domain;
	//struct hostent * he;
	//gethostname(host, 32);
	//printf("%s", host);
	//he = gethostbyname(host);
	//printf("a %s\n", he->h_name);
	//domain = strchr(he->h_name, '.');
	//printf("b\n");
	//if (domain == NULL) {
	//	printf("Brak domeny\n");
	//	return -6;
	//}
	//sprintf(client_name, "%s.%s", host, domain);
	srand(time(NULL));
	int x = rand()%100;
	sprintf(client_name, "testklient%d", x);
	char path[64];
	printf("Generuję ścieżkę\n");
	getcwd(path, 128*sizeof(char));
	sprintf(client_path, "%s/%s", path, client_name);
	printf("Nazwa klienta: %s\nŚcieżka do klienta: %s\n", client_name, client_path);
	if (local) {
		if ((socket_des = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) {
			perror("socket");
			return -7;
		}
	} else {
		if ((socket_des = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
			perror("socket");
			return -8;
		}		
	}
	struct sockaddr_un srv_unix_address;
	struct sockaddr_un cl_unix_address;
	struct sockaddr_in srv_inet_address;
	struct sockaddr_in cl_inet_address;
	struct sockaddr* srv_address;
	struct sockaddr* cl_address;
	socklen_t address_size;
	if (local == 1) {
		srv_unix_address.sun_family = AF_UNIX;
		strcpy(srv_unix_address.sun_path, server_path);
		srv_address = (struct sockaddr *)&srv_unix_address;
		cl_unix_address.sun_family = AF_UNIX;
		strcpy(cl_unix_address.sun_path, client_path);
		cl_address = (struct sockaddr *)&cl_unix_address;
		address_size = sizeof(struct sockaddr_un);
	} else {
		srv_inet_address.sin_family = AF_INET;
		inet_pton(AF_INET, ip, &(srv_inet_address.sin_addr.s_addr));
		srv_inet_address.sin_port = htons(server_port);
		srv_address = (struct sockaddr *)&srv_inet_address;
		cl_inet_address.sin_family = AF_INET;
		cl_inet_address.sin_addr.s_addr = htonl(INADDR_ANY);
		cl_inet_address.sin_port = htons(1024 + rand() % 64511);
		cl_address = (struct sockaddr *)&cl_inet_address;
		address_size = sizeof(struct sockaddr_in);
	}
	if (bind(socket_des, cl_address, address_size) == -1) {
		perror("bind");
		return -9;
	}
	if (pthread_create(&thread, NULL, request, NULL) == -1) {
		perror("pthread_create");
		return -10;
	}
	task_type task;
	strcpy(task.name, client_name);
	task.action = 0;
	pthread_mutex_lock(&mutex);
	if (sendto(socket_des, (void *)&task, sizeof(task), 0, srv_address, address_size) == -1) {
		perror("sendto");
		return -11;
	}
	list response;
	if (recv(socket_des, (void *)&response, sizeof(response), 0) == -1) {
		perror("recv");
		return -12;
	}
	pthread_mutex_unlock(&mutex);
	int i;
	for (i = 0; i < 10 && strlen(response.array[i]) > 0; i++) {
		printf("%d %s\n", i, response.array[i]);
	}
	while (1) {
		int action;
		printf("Wybierz zadanie:\n1 - zapytaj o listę zarejestrowanych klientów\n2 - przekaż polecenie do wykonania przez innego klienta\n3 - wyloguj się\n");
		scanf("%d", &action);
		if (action == 1) {
			task.action = 1;
			pthread_mutex_lock(&mutex);
			if (sendto(socket_des, (void *)&task, sizeof(task), 0, srv_address, address_size) == -1) {
				perror("sendto");
				return -13;
			}
			if (recv(socket_des, (void *)&response, sizeof(response), 0) == -1 ){
				perror("recv");
				return -14;
			}
			pthread_mutex_unlock(&mutex);
			for (i = 0; i < 10 && strlen(response.array[i]) > 0; i++) {
				printf("%d %s\n", i, response.array[i]);
			}			
		} else if (action == 2) {
			printf("Wybierz klienta u którego chcesz wykonać polecenie: \n");
			scanf("%d", &(task.client));
			getchar();
			task.action = 2;
			printf("Podaj polecenie do wykonania: \n");
			fgets(task.command, 256, stdin);
			printf("%s\n",task.command);
			printf("Pobrałem komendę, wysyłam\n");
			pthread_mutex_lock(&mutex);
			if (sendto(socket_des, (void *)&task, sizeof(task), 0, srv_address, address_size) == -1) {
				perror("sendto");
				return -15;
			}
			printf("Czekam na odpowiedź\n");
			char * buffer = (char *)malloc(sizeof(char)*2000);
			if (buffer == NULL) {
				perror("malloc");
			}
			if (recv(socket_des, (void *)&buffer, sizeof(char)*2000, 0) == -1) {
				perror("recv");
				return -16;
			}
			pthread_mutex_unlock(&mutex);
			printf("Wykonane polecenie u innego klienta zwróciło: \n%s\n", buffer);
		} else if (action == 3) {
			task.action = 3;
			pthread_mutex_lock(&mutex);
			if (sendto(socket_des, (void *)&task, sizeof(task), 0, srv_address, address_size) == -1) {
				perror("sendto");
				return -17;
			}
			pthread_mutex_unlock(&mutex);
			return 0;
		} else {
			printf("Wybrano nieprawidłową opcję\n");
		}
	}
	return 0;
}


